package com.ssm.service;

import com.hqj.FileUtil;
import com.hqj.ReturnUtil;
import com.ssm.dao.FilesDao;
import com.ssm.entity.Commons;
import com.ssm.entity.Down;
import com.ssm.entity.Files;
import net.lingala.zip4j.ZipFile;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.model.enums.CompressionLevel;
import net.lingala.zip4j.model.enums.CompressionMethod;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

@Service
public class FilesServiceI implements BaseService<Files> {

    @Autowired
    private FilesDao fd;

    public Files get(Files files) {
        List<Files> list = this.find(files);
        return list.size()>0?list.get(0):null;
    }

    public List<Files> find(Files files) {
        List<Files> list = fd.find(files);
        if(files.getFileSize()!=null){
            List<Integer> ids = new ArrayList<Integer>();
            getFileIds(list, files.getFileSize().intValue(),ids);
            //去掉ids对应的记录
            List<Files> lis = new ArrayList();
            for(Files f:list){
                int id = f.getId();
                boolean b = true;//默认，说明该不能去除，否则去除
                for(int mid:ids){
                    if(mid == id){
                        b = false;
                        break;
                    }
                }
                if(b){
                    lis.add(f);
                }
            }
            return lis;
        }
        return list;
    }


    public Map<String,Object> createDir(String dirName,String pId){
        boolean b = false;
        String path = ReturnUtil.BASE_PATH;
        int parentId = 0;
        if(!pId.equals("0")){
            parentId = Integer.parseInt(pId);
            Files f = new Files();
            f.setId(parentId);
            f = this.get(f);
            path = f.getFilePath();
        }
        File f1 = new File(path);
        File f2 = new File(f1,dirName);

        String newDirName = new Date().getTime()+"";

        //判断该路径是否已经存在，如果存在自动添加副本
        f2 = FileUtil.createNewDirName(f2,newDirName);

        b = FileUtil.createDir(f2);
        int i = 0;
        if(b) {
            //把新建文件夹的信息存储到数据库
            Files files = new Files();
            files.setParentId(parentId);
            files.setNewFileName(newDirName);
            files.setOldFileName(dirName);
            files.setFileSize(0L);
            files.setFilePath(f2.getAbsolutePath());
            files.setFileType("dir");
            files.setCreateTime(new Date());
            files.setUpdateTime(new Date());
            i = fd.add(files);

        }
        return ReturnUtil.returnMap(b&&i>0,dirName+"-文件夹");
    }



    public Map<String, Object> add(Files files) {
        return null;
    }

    public Map<String, Object> edit(Files files) {
        files.setUpdateTime(new Date());
        int i = fd.edit(files);
        return ReturnUtil.returnMap(i>0,"保存");
    }

    public Map<String, Object> remove(Files files) {
        return null;
    }

    public Map<String, Object> remove(int fid) {
        Files fs = new Files();
        fs.setId(fid);
        fs = this.get(fs);
        String filePath = fs.getFilePath();

        //通过该路径可以获取该路径下所有的文件
        File f = new File(filePath);
        List<String> list = new ArrayList<String>();
        list = getFileName(f,list);

        //删除数据库对应的信息
        int i = fd.batchRemove(list);
        //执行递归删除本地文件
        if(i>0){
            removeFiles(f);
        }
        return ReturnUtil.returnMap(i>0,"删除");
    }

    public Map<String,Object> saveFile(MultipartFile files[],int id){
        String path = ReturnUtil.BASE_PATH;
        int parentId = 0,i = 0;
        if(id!=0){
            parentId = id;
            Files f = new Files();
            f.setId(id);
            f = this.get(f);
            path = f.getFilePath();
        }
        try {
            if(files!=null&&files.length>0){
                List<Files> list = new ArrayList<Files>();
                //遍历文件数组
                for(MultipartFile file:files){
                    //获取文件名
                    String oldFileName = file.getOriginalFilename();
                    //中文乱码处理
                    oldFileName = new String(oldFileName.getBytes("iso-8859-1"),"utf-8");
                    //获取后缀名
                    String suffix = oldFileName.substring(oldFileName.lastIndexOf(".")+1);
                    //创建新的文件名称
                    String newFileName = new Date().getTime()+"."+suffix;
                    //创建文件
                    File f = new File(path,newFileName);

                    //创建文件
                    FileUtil.createFile(f);
                    //保存文件到本地服务器
                    file.transferTo(f);

                    Files fs = new Files();
                    fs.setParentId(parentId);
                    fs.setOldFileName(oldFileName);
                    fs.setNewFileName(newFileName);
                    fs.setFileType("file");
                    fs.setFileSuffix(suffix);
                    fs.setTypeName(Commons.getTypeName(suffix));
                    fs.setFileSize(file.getSize());
                    fs.setFilePath(f.getAbsolutePath());
                    fs.setCreateTime(new Date());
                    fs.setUpdateTime(new Date());
                    list.add(fs);
                }
                i = fd.batchAdd(list);
            }


        }catch (Exception e){
            e.printStackTrace();
        }

        return ReturnUtil.returnMap(i>0,"文件上传");
    }

    public Map<String,Object> saveDir(MultipartFile files[],int id){
        int i = 0,parentId = id;
        String path = ReturnUtil.BASE_PATH;
        Files ff = new Files();
        if(parentId!=0){
            ff.setId(id);
            ff = this.get(ff);
            path = ff.getFilePath();
        }
        for(MultipartFile file:files){
            try {
                if(file instanceof CommonsMultipartFile){
                    CommonsMultipartFile f = (CommonsMultipartFile)file;
                    String pathName = f.getFileItem().getName();//文件夹/.../.../文件.后缀
                    //分割
                    String pns[] = pathName.split("/");

                    for(int a=0;a<pns.length;a++){

                        String pn = pns[a];
                        //中文乱码
                        pn = new String(pn.getBytes("iso-8859-1"),"utf-8");
                        Date d = new Date();
                        String newFileName = d.getTime()+"";
                        Files fs = new Files();
                        fs.setOldFileName(pn);
                        fs.setParentId(parentId);
                        fs.setCreateTime(d);
                        fs.setUpdateTime(d);
                        if(a+1 == pns.length){//到文件了，不是文件夹
                            String suffix = pn.substring(pn.lastIndexOf(".")+1);
                            File f2 = new File(path,newFileName+"."+suffix);
                            FileUtil.createFile(f2);
                            file.transferTo(f2);
                            fs.setNewFileName(newFileName+"."+suffix);
                            fs.setFileType("file");
                            fs.setFileSuffix(suffix);
                            fs.setFileSize(file.getSize());
                            fs.setFilePath(f2.getAbsolutePath());
                            fs.setTypeName("");
                            //回到初始状态
                            parentId = id;
                            path = ReturnUtil.BASE_PATH;
                            if(parentId!=0){
                                path = ff.getFilePath();
                            }
                        }else{
                            //判断数据库是否已经存在该文件夹

                            fs.setFileType("dir");
                            Files fs1 = this.get(fs);
                            if(fs1!=null){//说明能在数据库查询到数据说明存在
                                parentId = fs1.getId();
                                path = fs1.getFilePath();
                                continue;
                            }
                            //文件夹不存在，则需要创建路径，及保存数据库获取id

                            File dirFile = new File(path,newFileName);
                            FileUtil.createDir(dirFile);
                            //重新设置路径，成为下一个循环文件夹的父路径
                            path = dirFile.getAbsolutePath();
                            fs.setFileSize(0L);
                            fs.setNewFileName(newFileName);
                            fs.setFileType("dir");
                            fs.setFilePath(path);

                        }
                        int b = fd.add(fs);
                        if(b<=0){
                            i=0;
                            break;
                        }
                        i++;
                        if(a+1 < pns.length) {
                            parentId = fs.getId();//获取新增成功的自增id，成功下一个文件夹的父id
                        }
                    }
                }


            }catch (Exception e){
                e.printStackTrace();
            }
        }
        return ReturnUtil.returnMap(i>0,"文件夹上传");
    }

    public void download(int id, HttpServletResponse res){
        //通过id获取下载文件的路径
        Files fs = new Files();
        fs.setId(id);
        fs = this.get(fs);
        String filePath = fs.getFilePath();
        File f = new File(filePath);
        String suffix = "";
        //判断是文件下载还是文件夹下
        if("dir".equals(fs.getFileType())&&f.isDirectory()){
            //对该文件夹进行压缩
            f = zipDir(f);
            suffix = ".zip";
        }

        //设置响应数据的编码格式
        res.setCharacterEncoding("utf-8");
        if(f.exists()){
            try {
                //获取文件名
                String oldFileName = fs.getOldFileName()+suffix;
                oldFileName = new String(oldFileName.getBytes("utf-8"),"iso-8859-1");
                res.setHeader("Content-Disposition","attachment;fileName="+oldFileName);
                res.setContentType("multipart/form-data");

                //打开字节输入流读取文件
                InputStream is = new FileInputStream(f);
                OutputStream os = res.getOutputStream();
                byte bs[] = new byte[1024];
                int i = 0;
                while((i=is.read(bs))>0){
                    os.write(bs,0,i);
                }
                os.close();
                is.close();


                //如果是文件夹下载，完成后要删除压缩包缓存文件
                if("dir".equals(fs.getFileType())){
                    zipDelCache(f);
                }
            }catch (Exception e){
                e.printStackTrace();
            }

        }else{
            String tip = "该文件不存在";
            System.out.println(tip);
        }

    }



    public static List<String> getFileName(File f,List<String> list){
        list.add(f.getName());
        //判断是路径还是文件
        if(f.isFile()){
            return list;
        }else{
            File files[] = f.listFiles();
            for(File file:files){
                getFileName(file,list);
            }
        }
        return list;
    }

    public static void removeFiles(File f){
        //如果是文件直接删除
        if(f.isFile()){
            f.delete();
        }else{
            File files[] = f.listFiles();
            for(File file:files){
                removeFiles(file);
                file.delete();
            }
            f.delete();
        }
    }

    public static void getFileIds(List<Files> files,int mid,List<Integer> ids){

        ids.add(mid);

        for(Files file:files){
            //判断mid  A是否与其他记录的parentId B相等，如果相等说明B记录是A记录的子记录
            //递归判断B记录是否有子记录，以此类推获取出mid 的所有子记录
            if(mid == file.getParentId()){
                getFileIds(files,file.getId(),ids);
            }
        }
    }

    //压缩文件夹
    public static File zipDir(File f){
        if(f.isFile()){
            return f;
        }
        try {
            //获取路径名称，也是压缩包的名称
            String zipName = f.getAbsolutePath()+".zip";
            //生成一个空的压缩文件
            ZipFile zf = new ZipFile(zipName);
            //创建压缩文件配置类
            ZipParameters zp = new ZipParameters();
            //压缩方式
            zp.setCompressionMethod(CompressionMethod.DEFLATE);
            //压缩级别
            zp.setCompressionLevel(CompressionLevel.NORMAL);

            //获取被压缩路径下的文件
            File fs[] = f.listFiles();
            for(File file:fs){
                if(file.isDirectory()){
                    zf.addFolder(new File(file.getPath()),zp);
                }else{
                    zf.addFile(file,zp);
                }
            }
            System.out.println("文件夹压缩完成");

            return new File(zipName);
        }catch (Exception e){
            System.out.println(e.getMessage());
        }

        return null;
    }

    //删除压缩包缓存
    public static void zipDelCache(File f){
        //获取文件名
       final String fileName = f.getName();
        //获取上层路径
        String parentPath = f.getParent();
        f = new File(parentPath);
        //获取该路径下所有的缓存zip文件
        File fs[] = f.listFiles(new FileFilter() {
            public boolean accept(File file) {
                String regex = fileName+"\\d+";
                return file.getName().matches(regex);
            }
        });
        for(File file:fs){
            file.delete();
        }
    }
}
